package pfq.demo.threads;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import pfq.demo.R;

/**
 * 面试题：多线程打印如何实现
 * <p>
 * 这里使用两个线程交替打印，从1到100
 * <p>
 * 思路：这是一道多线程处理共享资源的问题，此处的共享资源就是数字，要实现交替打印，需要明白1到100中，不是奇数就是偶数，所以两线程有一个打印奇数，一个打印偶数，
 * 假设线程1打印奇数，线程2打印偶数，各线程在处理数字的时候，首先要对数字进行加锁，保证资源的独占性，然后判断当前是否轮到自己打印，如果不是，则wait，挂起自己，释放锁，让另一个线程去处理；
 * 如果是，则处理并打印，然后notify其他线程
 */
public class MultipleThreadsPrintActivity extends AppCompatActivity {

    private TextView mNumTextView;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);

            mNumTextView.setText((String) msg.obj);

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_multiple_threads_print);

        mNumTextView = findViewById(R.id.activity_multiple_threads_print_textview);

        // 创建一个Num，准备打印资源
        final Num num = new Num();

        findViewById(R.id.activity_multiple_threads_print_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 线程1打印奇数
                Task task1 = new Task(num, mHandler, false);
                // 线程2打印偶数
                Task task2 = new Task(num, mHandler, true);
                Thread thread1 = new Thread(task1);
                Thread thread2 = new Thread(task2);

                thread1.start();
                thread2.start();
            }
        });


    }

    static class Num {
        int num = 0;
    }

    static class Task implements Runnable {

        private final Num num;

        private Handler handler;

        // 是否打印偶数，是：打印偶数；否：打印奇数
        private boolean isPrintEvenNum;

        Task(Num num, Handler handler, boolean isPrintEvenNum) {
            this.num = num;
            this.handler = handler;
            this.isPrintEvenNum = isPrintEvenNum;
        }

        boolean needWait() {
            // 如果是打印偶数
            if (isPrintEvenNum) {
                // 那当前数字如果是偶数，则此次打印就不是自己，就应该等待
                return this.num.num % 2 == 0;
            } else {
                // 奇数同理
                return this.num.num % 2 != 0;
            }
        }

        @Override
        public void run() {

            // 多线程交替打印数字，那数字就是共享资源，所以此处的锁要加在这个数字上
            synchronized (this.num) {
                try {
                    // 数字没打印完就不能退出循环
                    while (this.num.num < 100) {

                        // 唤醒所有因等待该资源释放锁的线程
                        this.num.notifyAll();

                        // 判断当前数字是不是自己处理，如果不是，就需要释放锁，挂起线程，进行等待
                        while (needWait()) {
                            // 在哪个资源上加锁，就要在哪个资源上释放锁
                            this.num.wait();
                        }

                        // 处理
                        this.num.num++;

                        // 发到主线程进行打印
                        Message message = Message.obtain();
                        message.obj = "当前线程：" + Thread.currentThread().getName() + ", Num：" + this.num.num;
                        handler.sendMessage(message);

                        Thread.sleep(200);

                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
